www.gusucode.com > VC++ P2P下载软件源代码-源码程序 > VC++ P2P下载软件源代码-源码程序\code\client\SimpleXML.cpp
//Download by http://www.NewXing.com /* * Copyright (C) 2001-2003 Jacek Sieka, j_s@telia.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdinc.h" #include "DCPlusPlus.h" #include "SimpleXML.h" string SimpleXML::escape(const string& aString, bool aAttrib, bool aReverse /* = false */) { string::size_type i; const char* chars = aAttrib ? "<&>'\"" : "<&>"; if(aReverse) { if(aString.find('&') == string::npos) { return aString; } else { string tmp = aString; while( (i=tmp.find("<")) != string::npos) { tmp.replace(i, 4, 1, '<'); } while( (i=tmp.find("&")) != string::npos) { tmp.replace(i, 5, 1, '&'); } while( (i=tmp.find(">")) != string::npos) { tmp.replace(i, 4, 1, '>'); } if(aAttrib) { while( (i=tmp.find("'")) != string::npos) { tmp.replace(i, 6, 1, '\''); } while( (i=tmp.find(""")) != string::npos) { tmp.replace(i, 6, 1, '"'); } } if( (i = tmp.find('\n')) != string::npos) { if(i > 0 && tmp[i-1] != '\r') { // This is a unix thing...decode it... i = 0; while( (i = tmp.find('\n', i) ) != string::npos) { if(tmp[i-1] != '\r') tmp.insert(i, 1, '\r'); i+=2; } } } return tmp; } } else { i = aString.find_first_of(chars); if(i == string::npos) { return aString; } else { string tmp = aString; do { switch(tmp[i]) { case '<': tmp.replace(i, 1, "<"); i+=4; break; case '&': tmp.replace(i, 1, "&"); i+=5; break; case '>': tmp.replace(i, 1, ">"); i+=4; break; case '\'': tmp.replace(i, 1, "'"); i+=6; break; case '"': tmp.replace(i, 1, """); i+=6; break; default: dcassert(0); } } while( (i = tmp.find_first_of(chars, i)) != string::npos); return tmp; } } dcasserta(0); } string SimpleXML::Tag::getAttribString() { string tmp; for(AttribIter i = attribs.begin(); i!= attribs.end(); ++i) { tmp.append(i->first); tmp.append("=\"", 2); tmp.append(needsEscape(i->second, true) ? escape(i->second, true) : i->second); tmp.append("\" ", 2); } if(tmp.size() > 0) { tmp.erase(tmp.size() - 1); } return tmp; } string SimpleXML::Tag::toXML(int indent) { if(children.empty()) { if(data.empty()) { if(attribs.empty()) { string tmp; tmp.reserve(indent + name.length() + 5); tmp.append(indent, '\t'); tmp.append(1, '<'); tmp.append(name); tmp.append("/>\r\n", 4); return tmp; } else { string attr = getAttribString(); string tmp; tmp.reserve(indent + name.length() + attr.length() + 6); tmp.append(indent, '\t'); tmp.append(1, '<'); tmp.append(name); tmp.append(1, ' '); tmp.append(attr); tmp.append("/>\r\n", 4); return tmp; } } else { if(attribs.empty()) { string tmp = escape(data, false); char* buf = new char[indent + name.length()*2 + tmp.length() + 10]; sprintf(buf, "%s<%s>%s</%s>\r\n", string(indent, '\t').c_str(), name.c_str(), tmp.c_str(), name.c_str()); tmp = buf; delete[] buf; return tmp; } else { string tmp = escape(data, false); string attrib = getAttribString(); char* buf = new char[indent + name.length()*2 + tmp.length() + attrib.length() + 10]; sprintf(buf, "%s<%s %s>%s</%s>\r\n", string(indent, '\t').c_str(), name.c_str(), attrib.c_str(), tmp.c_str(), name.c_str()); tmp = buf; delete[] buf; return tmp; } } } else if(attribs.empty()) { string tmp(indent, '\t'); tmp.append(1, '<'); tmp.append(name); tmp.append(">\r\n", 3); for(Iter i = children.begin(); i!=children.end(); ++i) { tmp.append((*i)->toXML(indent + 1)); } tmp.append(indent, '\t'); tmp.append("</", 2); tmp.append(name); tmp.append(">\r\n", 3); return tmp; } else { string tmp(indent, '\t'); tmp.append(1, '<'); tmp.append(name); tmp.append(1, ' '); tmp.append(getAttribString()); tmp.append(">\r\n", 3); for(Iter i = children.begin(); i!=children.end(); ++i) { tmp.append((*i)->toXML(indent + 1)); } tmp.append(indent, '\t'); tmp.append("</", 2); tmp.append(name); tmp.append(">\r\n", 3); return tmp; } } /** * The same as the version above, but writes to a file instead...yes, this could be made * with streams and only one code set but streams are slow...the file f should be a buffered * file, otherwise things will be very slow (I assume write is not expensive and call it a lot */ void SimpleXML::Tag::toXML(int indent, File* f) { if(children.empty()) { if(data.empty()) { if(attribs.empty()) { for(int i = 0; i < indent; i++) f->write("\t", 1); f->write("<", 1); f->write(name); f->write("/>\r\n", 4); return; } else { for(int i = 0; i < indent; i++) f->write("\t", 1); f->write("<", 1); f->write(name); f->write(" ", 1); f->write(getAttribString()); f->write("/>\r\n", 4); return; } } else { if(attribs.empty()) { for(int i = 0; i < indent; i++) f->write("\t", 1); f->write("<", 1); f->write(name); f->write(">", 1); f->write(needsEscape(data, false) ? escape(data, false) : data); f->write("</", 2); f->write(name); f->write(">\r\n", 3); return; } else { for(int i = 0; i < indent; i++) f->write("\t", 1); f->write("<", 1); f->write(name); f->write(" ", 1); f->write(getAttribString()); f->write(">", 1); f->write(needsEscape(data, false) ? escape(data, false) : data); f->write("</", 2); f->write(name); f->write(">\r\n", 3); return; } } } else if(attribs.empty()) { int i; for(i = 0; i < indent; i++) f->write("\t", 1); f->write("<", 1); f->write(name); f->write(">\r\n", 3); for(Iter it = children.begin(); it!=children.end(); ++it) { (*it)->toXML(indent + 1, f); } for(i = 0; i < indent; i++) f->write("\t", 1); f->write("</", 2); f->write(name); f->write(">\r\n", 3); return; } else { int i; for(i = 0; i < indent; i++) f->write("\t", 1); f->write("<", 1); f->write(name); f->write(" ", 1); f->write(getAttribString()); f->write(">\r\n", 3); for(Iter it = children.begin(); it!=children.end(); ++it) { (*it)->toXML(indent + 1, f); } for(i = 0; i < indent; i++) f->write("\t", 1); f->write("</", 2); f->write(name); f->write(">\r\n", 3); return; } } bool SimpleXML::findChild(const string& aName) throw() { dcassert(current != NULL); if(found && currentChild != current->children.end()) currentChild++; while(currentChild!=current->children.end()) { if((*currentChild)->name == aName) { found = true; return true; } else currentChild++; } return false; } void SimpleXML::Tag::fromXML(const string& tmp, string::size_type start, string::size_type end, int aa /* = 0 */) throw(SimpleXMLException) { string::size_type i = start; string::size_type j; dcassert(tmp.size() > 0); while( (j = tmp.find('<', i)) != string::npos ) { // Check that we have at least 3 more characters as the shortest valid xml tag is <a/>... if((j + 3) > tmp.size()) { throw SimpleXMLException("Too few characters after <"); } if( (j+3) > end) break; Ptr child = NULL; i = j + 1; if(tmp[i] == '?') { // <? processing instruction ?>, ignore... i = tmp.find("?>", i); if(i == string::npos) { throw SimpleXMLException("Missing '?>'"); } continue; } if(tmp[i] == '!' && tmp[i+1] == '-' && tmp[i+2] == '-') { // <!-- comment -->, ignore... i = tmp.find("-->", i); if(i == string::npos) { throw SimpleXMLException("Missing '-->'"); } continue; } // Alright, we have a real tag for sure... j = tmp.find_first_of(" >", i); if(j == string::npos) { throw("Missing '>'"); } string name; string::size_type tagStart = 0; string::size_type tagEnd = 0; bool simpleTag = false; if(tmp[j] == ' ') { name = tmp.substr(i, j-i); if(name.empty()) { throw SimpleXMLException("Tag without name"); } i = j+1; j = tmp.find('>', i); if(j == string::npos) { throw SimpleXMLException("Missing '>' around " + name); } tagStart = i; if(tmp[j-1] == '/') { tagEnd = j - 1; simpleTag = true; } else { tagEnd = j; } } else { if(tmp[j-1] == '/') { simpleTag = true; name = tmp.substr(i, j-i-1); } else { name = tmp.substr(i, j-i); } } i = j + 1; string::size_type x = tagStart; string::size_type y; child = new Tag(name, Util::emptyString, this, aa); while( (x < tagEnd) && (y=tmp.find('=', x)) != string::npos && (y < tagEnd)) { x = tmp.find_first_not_of(' ', x); string::size_type x2 = y + 2; string::size_type y2 = tmp.find('"', x2); if(y2 == string::npos || y2 > tagEnd) { throw SimpleXMLException("Missing '\"' around " + name); } child->attribs.push_back(make_pair(tmp.substr(x, y-x), tmp.substr(x2, y2-x2))); if(needsEscape(child->attribs.back().second, true, true)) child->attribs.back().second = escape(child->attribs.back().second, true, true); x = y2 + 1; } if(!simpleTag) { string endTag = "</" + name + ">"; j = tmp.find(endTag, i); if(j == string::npos) { throw SimpleXMLException("Missing end tag around " + name); } string::size_type dataPos = tmp.find('<', i); if(dataPos != string::npos && dataPos < j) { child->fromXML(tmp, i, j, aa); } else { child->data = tmp.substr(i, j-i); if(needsEscape(child->data, false, true)) child->data = escape(child->data, false, true); } i = j + endTag.length(); } children.push_back(child); } } void SimpleXML::addTag(const string& aName, const string& aData /* = "" */) throw(SimpleXMLException) { if(aName.empty()) { throw SimpleXMLException("Empty tag names not allowed"); } if(current == root) { if(current->children.empty()) { current->children.push_back(new Tag(aName, aData, root, attribs)); currentChild = current->children.begin(); } else { throw SimpleXMLException("Only one root tag allowed"); } } else { current->children.push_back(new Tag(aName, aData, current, attribs)); currentChild = current->children.end() - 1; } } void SimpleXML::addAttrib(const string& aName, const string& aData) throw(SimpleXMLException) { if(current==root) throw SimpleXMLException("No tag is currently selected"); current->attribs.push_back(make_pair(aName, aData)); } void SimpleXML::addChildAttrib(const string& aName, const string& aData) throw(SimpleXMLException) { checkChildSelected(); (*currentChild)->attribs.push_back(make_pair(aName, aData)); } void SimpleXML::fromXML(const string& aXML) throw(SimpleXMLException) { if(root) { delete root; } root = new Tag("BOGUSROOT", Util::emptyString, NULL, 0); root->fromXML(aXML, 0, aXML.size(), attribs); if(root->children.size() != 1) { throw SimpleXMLException("Invalid XML file, missing or multiple root tags"); } current = root; currentChild = current->children.begin(); } /** * @file * $Id: SimpleXML.cpp,v 1.19 2003/04/15 10:13:55 arnetheduck Exp $ */